package com.hbpu.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hbpu.usercenter.common.ErrorCode;
import com.hbpu.usercenter.dto.*;
import com.hbpu.usercenter.exception.BusinessException;
import com.hbpu.usercenter.mapper.TeamMapper;
import com.hbpu.usercenter.pojo.Team;
import com.hbpu.usercenter.pojo.User;
import com.hbpu.usercenter.pojo.UserTeam;
import com.hbpu.usercenter.service.TeamService;
import com.hbpu.usercenter.service.UserService;
import com.hbpu.usercenter.service.UserTeamService;
import com.hbpu.usercenter.vo.TeamUserVO;
import com.hbpu.usercenter.vo.UserVO;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * @author 马可
 * @description 针对表【team(队伍)】的数据库操作Service实现
 * @createDate 2025-09-22 22:16:15
 */
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team> implements TeamService {

    private final UserService userService;
    private final UserTeamService userTeamService;

    public TeamServiceImpl(UserService userService, UserTeamService userTeamService) {
        this.userService = userService;
        this.userTeamService = userTeamService;
    }


    /**
     * 添加队伍的方法
     *
     * @param teamDTO 前端返回数据所映射的对象
     * @param request 用户请求
     * @return 添加成功返回true
     */
    @Override
    @Transactional
    public synchronized Long addTeam(TeamDTO teamDTO, HttpServletRequest request) {
        // 检查队伍人数
        if (teamDTO.getMaxNum() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数上限为20！");
        }
        // 检查队伍标题格式
        if (teamDTO.getName().length() > 20) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题上限20！");
        }
        // 检查队伍描述格式
        if (teamDTO.getDescription().length() > 512) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述上限512！");
        }
        // 检查私有队伍的密码格式
        if (teamDTO.getStatus() == 1) {
            if (teamDTO.getPassword() == null || teamDTO.getPassword().isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "私有队伍必须设置密码！");
            }
            if (teamDTO.getPassword().length() != 6) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍密码必须为6位数字！");
            }
        }
        // 检查公开队伍是否有密码
        if (teamDTO.getStatus() == 0 && StringUtils.hasLength(teamDTO.getPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "公开队伍不得设置密码！");
        }
        // 检查队伍截止时间
        if (!teamDTO.getExpireTime().isAfter(LocalDateTime.now())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "日期必须晚于当前时间！");
        }
        //从用户-队伍表中查询用户创建了多少队伍
        LambdaQueryWrapper<UserTeam> teamLambdaQueryWrapper = new LambdaQueryWrapper<>();
        teamLambdaQueryWrapper.eq(UserTeam::getUserId, userService.getCurrentUser(request).getId());
        long count = userTeamService.count(teamLambdaQueryWrapper);
        if (count > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "个人创建队伍上限为5！");
        }
        // 将前端传输的注册对象转换为team对象并插入team表
        Team team = new Team();
        BeanUtils.copyProperties(teamDTO, team);
        boolean saveTeam = this.save(team);
        if (!saveTeam) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建队伍失败！");
        }
        //将信息存入team-user对象并插入UserTeam表
        UserTeam userTeam = new UserTeam();
        userTeam.setUserId(team.getUserId());
        userTeam.setTeamId(team.getId());
        userTeam.setJoinTime(LocalDateTime.now());
        boolean saveUserTeam = userTeamService.save(userTeam);
        if (!saveUserTeam) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "创建加入记录失败！");
        }

        return team.getId();
    }

    /**
     * 获取所有队伍
     *
     * @return 返回一个TeamUserVO类型的队伍列表
     */
    @Override
    public List<TeamUserVO> listTeam() {
        //获取所有team
        List<Team> list = this.list(new LambdaQueryWrapper<Team>().ge(Team::getExpireTime, LocalDateTime.now()));
        if (list.isEmpty()) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        // 将所有的team对象都一一映射到TeamUserVo包装对象
        return list.stream().map(team -> {
            // 创建team-user包装对象
            TeamUserVO teamUserVO = new TeamUserVO();
            BeanUtils.copyProperties(team, teamUserVO);
            //使用teamid去用户-队伍表中去查询记录
            List<UserTeam> userTeamList = userTeamService.list(new LambdaQueryWrapper<UserTeam>().eq(UserTeam::getTeamId, team.getId()));
            //根据查询记录中的用户id去查询用户信息
            //将用户信息映射到UserVO
            //然后添加到TeamUserVO的加入该队伍的用户的属性中
            if (!userTeamList.isEmpty()) {
                List<Long> userIdList = userTeamList.stream().map(UserTeam::getUserId).toList();
                List<User> userList = userService.list(new LambdaQueryWrapper<User>().in(User::getId, userIdList));
                List<UserVO> userVOList = userList.stream().map(user -> {
                    UserVO userVO = new UserVO();
                    BeanUtils.copyProperties(user, userVO);
                    return userVO;
                }).toList();
                teamUserVO.setUserVOList(userVOList);
            }
            //将处理后的TeamUserVo返回
            return teamUserVO;
        }).toList();
    }

    /**
     * 更新队伍信息的方法
     *
     * @param teamDTO 前端返回数据所映射的对象
     * @param request 用户请求
     * @return 更新成功返回true
     */
    @Override
    public Boolean updateTeam(TeamDTO teamDTO, HttpServletRequest request) {
        UserDTO currentUser = userService.getCurrentUser(request);
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "当前用户不存在或已经被禁用！");
        }
        if (teamDTO.getId() == null || teamDTO.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        if (teamDTO.getStatus() == 1) {
            if (teamDTO.getPassword() == null || teamDTO.getPassword().isEmpty()) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "私有队伍必须设置密码！");
            }
            if (teamDTO.getPassword().length() != 6) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍密码必须为6位数字！");
            }
        }
        Team oldTeam = this.getById(teamDTO.getId());
        if (oldTeam == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "要修改的队伍不存在");
        }
        if (!Objects.equals(oldTeam.getUserId(), currentUser.getId()) && !userService.isAdmin(request)) {
            throw new BusinessException(ErrorCode.NO_AUTH);
        }
        Team newTeam = new Team();
        BeanUtils.copyProperties(teamDTO, newTeam);
        return this.updateById(newTeam);
    }

    /**
     * 处理加入队伍的方法
     *
     * @param joinTeamDTO 包含加入队伍数据的包装类
     * @return 加入成功返回true
     */
    @Override
    public Boolean joinTeam(JoinTeamDTO joinTeamDTO) {
        //在数据库中查询该用户加入队伍的数量
        long joinTeamNum = userTeamService.count(new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getUserId, joinTeamDTO.getUserId())
                .ne(UserTeam::getIsDelete, 1)
        );
        // 最多加入五个队伍
        if (joinTeamNum > 5) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多加入五个队伍！");
        }
        // 根据TeamID来查询队伍
        Team team = this.getById(joinTeamDTO.getTeamId());
        // 判断加入的队伍是否存在
        if (team == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "你要加入的队伍不存在");
        }
        if (team.getStatus() == 0 && StringUtils.hasLength(joinTeamDTO.getPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "公开队伍参数中不应有密码！");
        }
        // 判断队伍如果为私有，应该存在密码，并检查密码格式
        String password = joinTeamDTO.getPassword();
        if (team.getStatus() == 1 && (password == null || password.length() != 6)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码为空或格式错误！");
        }
        // 检查密码是否正确
        if (team.getStatus() == 1 && !team.getPassword().equals(joinTeamDTO.getPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误！");
        }
        // 根据要加入的队伍的id去数据库中查询该队伍所有的加入记录
        List<UserTeam> userTeamList = userTeamService.list(new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getTeamId, joinTeamDTO.getTeamId())
        );
        // 检查当前用户是否已经加入了该队伍
        if (userTeamList.stream()
                .map(UserTeam::getUserId)
                .anyMatch(userId -> userId.equals(joinTeamDTO.getUserId()))) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "无法加入已经加入的队伍！");
        }
        // 从UserTeam表中查询当前队伍已加入的用户的数量
        long teamCurrentCount = userTeamService.count(new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getTeamId, joinTeamDTO.getTeamId())
        );
        // 检查用户数量是否已经超过了当前队伍所设置的人数上限
        if (teamCurrentCount == team.getMaxNum()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数已满");
        }
        // 创建一个UserTeam对象以便插入数据
        UserTeam userTeam = new UserTeam();
        // 将dto包装类映射成为UserTeam对象
        BeanUtils.copyProperties(joinTeamDTO, userTeam);
        userTeam.setJoinTime(LocalDateTime.now());
        // 执行插入操作
        boolean save = userTeamService.save(userTeam);
        if (!save) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "插入失败！");
        }
        return true;
    }

    /**
     * 用于处理退出队伍的请求的方法
     *
     * @param quitTeamDTO 包含退出队伍数据的DTO封装类
     * @return 退出成功返回false
     */
    @Override
    @Transactional
    public Boolean quitTeam(QuitTeamDTO quitTeamDTO) {
        // 判断队伍id参数是否错误
        if (quitTeamDTO.getTeamId() == null || quitTeamDTO.getTeamId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        //判断队伍是否存在
        Team team = this.getById(quitTeamDTO.getTeamId());
        if (team == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "队伍不存在！");
        }
        // 判断是否已经加入了该队伍
        UserTeam isJoin = userTeamService.getOne(new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getUserId, quitTeamDTO.getUserId())
                .eq(UserTeam::getTeamId, quitTeamDTO.getTeamId())
        );
        if (isJoin == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "没有加入该队伍，无法退出！");
        }
        // 判断当前队伍是否只有一个用户，如果只有一个用户，退出队伍后直接删除队伍
        long teamUserNum = userTeamService.count(new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getTeamId, quitTeamDTO.getTeamId())
        );
        if (teamUserNum == 1) {
            boolean teamResult = this.removeById(quitTeamDTO.getTeamId());
            boolean userTeamRemoveResult = userTeamService.remove(new LambdaQueryWrapper<UserTeam>()
                    .eq(UserTeam::getTeamId, quitTeamDTO.getTeamId())
                    .eq(UserTeam::getUserId, quitTeamDTO.getUserId())
            );
            if (teamResult && userTeamRemoveResult) {
                return true;
            }
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除失败！");
        }
        // 判断当前用户是否是队伍的队长，如果是，退出队伍是将队长自动移交给加入时间第二早的用户
        if (team.getUserId().equals(quitTeamDTO.getUserId())) {
            // 查询当前队伍的所有用户的加入信息
            List<UserTeam> userTeamList = userTeamService
                    .list(new LambdaQueryWrapper<UserTeam>()
                            .eq(UserTeam::getTeamId, quitTeamDTO.getTeamId())
                    );
            // 从查询的列表中创建一个流
            userTeamList.stream()
                    //从当前流中把自己过滤掉
                    .filter(userTeam -> !userTeam.getUserId().equals(quitTeamDTO.getUserId()))
                    // 使用比较方法（默认升序，从小到大）来排序加入时间，然后使用min方法取加入时间最早的
                    .min(Comparator.comparing(UserTeam::getJoinTime))
                    // 如果存在则把要退出的的队长设置为该加入时间第二早的用户，完成队长的转交
                    .ifPresent(userTeam -> team.setUserId(userTeam.getUserId()));
            // 更新数据库，应用队长的变更操作
            boolean updateResult = this.updateById(team);
            boolean userTeamReamovResult = userTeamService.remove(new LambdaQueryWrapper<UserTeam>()
                    .eq(UserTeam::getTeamId, quitTeamDTO.getTeamId())
                    .eq(UserTeam::getUserId, quitTeamDTO.getUserId())
            );
            // 如果没有更新成功，抛出异常
            if (!updateResult || !userTeamReamovResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "队伍转交时失败或出现异常！");
            }
            // 更新成功返回true
            return true;
        }

        // 非队长的话直接进行退出操作
        boolean quitResult = userTeamService.remove(
                new LambdaQueryWrapper<UserTeam>()
                        .eq(UserTeam::getTeamId, quitTeamDTO.getTeamId())
                        .eq(UserTeam::getUserId, quitTeamDTO.getUserId())
        );
        if (!quitResult) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "退出失败！");
        }
        return true;
    }

    /**
     * 用于处理删除队伍请求的方法
     * @param deleteTeamDTO 包含删除队伍数据的DTO封装类
     * @return 删除成功返回true
     */
    @Override
    @Transactional
    public Boolean deleteTeam(DeleteTeamDTO deleteTeamDTO) {
        // 检查当前队伍是否存在
        Team team = this.getById(deleteTeamDTO.getTeamId());
        if (team == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "你要删除的队伍不存在");
        }
        // 检查用户是否有删除队伍的权限
        if (!team.getUserId().equals(deleteTeamDTO.getUserId())) {
            throw new BusinessException(ErrorCode.NO_AUTH, "你不是该队伍的拥有者，无法删除！");
        }
        // 执行删除操作
        boolean deleteTeamResult = this.removeById(deleteTeamDTO.getTeamId());
        boolean deleteUserTeamResult = userTeamService.remove(new LambdaQueryWrapper<UserTeam>()
                .eq(UserTeam::getTeamId, deleteTeamDTO.getTeamId())
        );
        if (deleteTeamResult && deleteUserTeamResult) {
            return true;
        } else {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "删除失败！");
        }
    }
}




